package dal;

import java.sql.*;
import java.util.*;

import util.RightUtil;
import model.*;

public class GenericDal<T extends IModel, TE extends IModelExt> {

	private Connection _dbConn = null;
	private T _utilModel;

	public GenericDal(T utilModel) {
		_utilModel = utilModel;
	}

	public GenericDal(T utilModel, Connection dbConn) {
		_utilModel = utilModel;
		_dbConn = dbConn;
	}

	private Connection getDbConnection() throws ClassNotFoundException,
			SQLException {
		if (_dbConn == null) {
			_dbConn = ConnectionProvider.genConnection();
		}
		return _dbConn;
	}

	public T select(T query) throws SQLException, ClassNotFoundException {
		T model = null;
		if (RightUtil.checkSelectRight(query)) {
			Connection conn = getDbConnection();
			PreparedStatement st = _utilModel.genSelectStatement(conn, query);
			try {
				ResultSet rs = st.executeQuery();
				model = (T) _utilModel.readFromResultSet(rs);
				rs.close();
			} catch (Exception e) {
				// TODO: handle exception
			} finally {
				conn.close();
			}
		}
		return model;
	}

	public List<T> selectList(TE query) throws SQLException,
			ClassNotFoundException {
		List<T> models = null;
		if (RightUtil.checkSelectListRight(query)) {
			Connection conn = getDbConnection();
			PreparedStatement st = _utilModel.genSelectListStatement(conn,
					query);
			try {
				ResultSet rs = st.executeQuery();
				models = new ArrayList<T>();
				while (rs.next()) {
					T model = (T) _utilModel.readFromResultSet(rs);
					models.add(model);
				}
				rs.close();
			} catch (SQLException e) {
				// TODO: handle exception
				throw e;
			} finally {
				conn.close();
			}
		}
		return models;
	}

	public int insert(T model) throws ClassNotFoundException, SQLException {
		int result = Integer.MIN_VALUE;
		if (RightUtil.checkInsertRight(model)) {
			Connection conn = getDbConnection();
			PreparedStatement st = _utilModel.genInsertStatement(conn, model);
			try {
				ResultSet rs = st.executeQuery();
				if (rs.next()) {
					result = rs.getInt(1);
				}
				rs.close();
			} catch (SQLException e) {
				// TODO: handle exception
				throw e;
			} finally {
				conn.close();
			}
		}
		return result;
	}

	public int update(T model) throws SQLException, ClassNotFoundException {
		int result = Integer.MIN_VALUE;
		if (RightUtil.checkUpdateRight(model)) {
			Connection conn = getDbConnection();
			PreparedStatement st = _utilModel.genUpdateStatement(conn, model);
			try {
				ResultSet rs = st.executeQuery();
				if (rs.next()) {
					result = rs.getInt(0);
				}
				rs.close();
			} catch (SQLException e) {
				// TODO: handle exception
				throw e;
			} finally {
				conn.close();
			}
		}
		return result;
	}

	public int delete(T query) throws SQLException, ClassNotFoundException {
		int result = Integer.MIN_VALUE;
		if (RightUtil.checkDeleteRight(query)) {
			Connection conn = getDbConnection();
			PreparedStatement st = _utilModel.genDeleteStatement(conn, query);

			try {
				ResultSet rs = st.executeQuery();
				if (rs.next()) {
					result = rs.getInt(1);
				}
				rs.close();
			} catch (SQLException e) {
				// TODO: handle exception
				throw e;
			} finally {
				conn.close();
			}
		}
		return result;
	}

	public int count(TE query) throws SQLException, ClassNotFoundException {
		int result = Integer.MIN_VALUE;
		if (RightUtil.checkCountRight(query)) {
			Connection conn = getDbConnection();
			PreparedStatement st = _utilModel.genCountStatement(conn, query);

			try {
				ResultSet rs = st.executeQuery();
				if (rs.next()) {
					result = rs.getInt(1);
				}
				rs.close();
			} finally {
				conn.close();
			}
		}
		return result;
	}

	public static int execute(PreparedStatement st) throws SQLException {
		ResultSet rs = st.executeQuery();
		int result = rs.getInt(0);
		rs.close();
		return result;
	}

	public List<T> executeQuery(PreparedStatement st) throws SQLException {
		ResultSet rs = st.executeQuery();
		List<T> models = new ArrayList<T>();
		while (rs.next()) {
			T model = (T) _utilModel.readFromResultSet(rs);
			models.add(model);
		}
		rs.close();
		return models;
	}

}
